package com.anlogic.sdk.tools.exetool;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.logging.log4j.Logger;

import com.anlogic.sdk.tools.IBspTool;
import com.anlogic.sdk.tools.model.DocInfo;
import com.anlogic.sdk.tools.model.DriverInfo;
import com.anlogic.sdk.tools.model.LibraryInfo;
import com.anlogic.sdk.tools.model.OSInfo;
import com.anlogic.sdk.tools.ui.BspToolView;
import com.anlogic.sdk.tools.ui.ProcessController;
import com.anlogic.sdk.tools.utils.ToolsUtils;
import com.anlogic.sdk.utils.JsonUtils;
import com.anlogic.sdk.utils.LogUtils;
import com.anlogic.sdk.utils.StringUtils;
import com.anlogic.sdk.utils.options.ChipType;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

public class ExeBspTool implements IBspTool {
	private static Logger logger = LogUtils.getLogger(ExeBspTool.class);
	
	private static final String BSP_TOOL = "bsp_tool";
	private static final String DR1X90_TOOL = "dr1x90_tool";
	private static final String PH1P35_TOOL = "ph1p35_tool";
	private static final String DR1M350_TOOL = "dr1m350_tool";
	private static final String SOC66080_TOOL = "soc66080_tool";
	private static final String CREATE_DEFAULT_MSS = "create_default_mss -mssfile %s -chip %s -proc %s -os %s";
	private static final String CREATE_MSS_FROM_HPF = "create_mss_from_hpf -hpf %s -mssfile %s -chip %s -proc %s -os %s";
	private static final String GET_PROCESSOR = "get_processor -mssfile %s";
	private static final String GET_OS = "get_os -mssfile %s";
	private static final String GET_DOC = "get_doc -mssfile %s";
	private static final String GET_DRIVERS = "get_drivers -mssfile %s";
	private static final String GET_DRIVER = "get_driver -mssfile %s -name %s";
	private static final String SET_DRIVER_VERSION = "set_driver_version -mssfile %s -name %s -version %s";
	private static final String ADD_DRIVER = "add_driver -mssfile %s -name %s -version %s";
	private static final String DELETE_DRIVER = "delete_driver -mssfile %s -name %s";
	private static final String GET_LIBRARIES = "get_libraries -mssfile %s";
	private static final String GET_LIBRARY = "get_library -mssfile %s -name";
	private static final String SET_LIBRARY_VERSION = "set_library_version -mssfile %s -name %s -version %s";
	private static final String ADD_LIBRARY = "add_library -mssfile %s -name %s -version %s";
	private static final String DELETE_LIBRARY = "delete_library -mssfile %s -name %s";
	private static final String RELOAD_MSSFILE = "reload_mssfile -mssfile %s";
	
	private static final String GENERATE_BSP_RESOURCE = "generate_bsp_sources -hpf %s -mssfile %s -bsp_loc %s";
	private static final String REGENERATE_BSP_RESOURCE = "regenerate_bsp_sources -mssfile %s -bsp_loc %s";
	private static final String UPDATE_BSP_HPF = "update_bsp_hpf -bsp_loc %s -hpf %s";

	private static final String GET_APP_NAMES = "get_app_names -os %s -chip %s -proc %s";
	private static final String GET_DRIVER_APP_NAMES = "get_driver_app_names -driver_name %s -os %s -chip %s -proc %s";
	private static final String GET_LINUX_APP_NAMES = "get_linux_app_names -chip %s -proc %s";
	private static final String GET_APP_DESC = "get_app_desc -name %s";
	private static final String GET_APP_LIBS = "get_app_libs -name %s";
	private static final String GET_APP_EXTRA_LIBS = "get_app_extra_libs -mssfile %s -name %s";
	private static final String GET_APP_BUILD_PROPERTIES = "get_app_build_properties -name %s";
	private static final String GENERATE_APP_RESOURCE = "generate_app_sources -bsp_loc %s -name %s -app_loc %s";
	private static final String UPDATE_APP_LINKSCRIPT = "update_app_linkscript -bsp_loc %s -app_loc %s";

	private static final String GET_CHIP_FROM_HPF = "get_chip_from_hpf -hpf %s";

	private static final String GET_INCLUDE_PATHS = "get_include_paths -dir %s";

	private static final String GET_LINK_SCRIPTS = "get_link_scripts -app_loc %s -chip %s -download %s";

	private static final String GET_OS_NAMES = "get_os_names";
	private static final String GET_DRIVER_NAMES = "get_driver_names";
	private static final String GET_LIBRARY_NAMES = "get_library_names";
	private static final String GET_OS_VERSIONS = "get_os_versions -name %s";
	private static final String GET_DRIVER_VERSIONS = "get_driver_versions -name %s";
	private static final String GET_LIBRARY_VERSIONS = "get_library_versions -name %s";
	private static final String GET_OS_FROM_CFGFILE = "get_os_from_cfgfile -name %s -version %s";
	private static final String GET_DRIVER_FROM_CFGFILE = "get_driver_from_cfgfile -name %s -version %s";
	private static final String GET_LIBRARY_FROM_CFGFILE = "get_library_from_cfgfile -name %s -version %s";
	
	private static final String PROCESS_APP_MAKEFILE = "process_app_makefile -bsp_loc %s -app_loc %s -name %s";

	private ExeTool exeTool;

	private String toolName = BSP_TOOL;

	private String chip;
	
	private ExeBspTool() {
		this.exeTool = new ExeTool("BSP Tool");
		this.toolName = BSP_TOOL;
	}
	
    private static class Holder {
        static final ExeBspTool INSTANCE = new ExeBspTool();
    }
    
	public static ExeBspTool getInstance() {
		return Holder.INSTANCE;
	}

	public void setToolName(String toolName) {
		this.toolName = toolName;
	}

	public void setToolNameByChip(String chipName) {
		if (ChipType.isDr1(chipName)) {
			this.toolName = DR1X90_TOOL;
		} else if (ChipType.isPh1p(chipName)) {
			this.toolName = PH1P35_TOOL;
		} else if (ChipType.isSOC66080(chipName)) {
			this.toolName = SOC66080_TOOL;
		} else if (ChipType.isDR1M350(chipName)) {
			this.toolName = DR1M350_TOOL;
		} else {
			this.toolName = BSP_TOOL;
		}
	}
	
	@Override
	public String getChip() {
		return this.chip;
	}
	
	@Override
	public void setChip(String chip) {
		this.chip = chip;
		setToolNameByChip(chip);
	}

	public void setPrintToConsole(boolean printToConsole) {
		this.exeTool.setPrintToConsole(printToConsole);
	}

	public void printStdOutMessage(String msg) {
		this.exeTool.printStdOutMessage(msg);
	}

	public void printStdErrMessage(String msg) {
		this.exeTool.printStdErrMessage(msg);
	}
	
	public String getExeToolCmd(String cmd) {
		String toolCmd = String.format("sw_cmd_tool %s %s", this.toolName, cmd);
		return toolCmd;
	}
	
	public String getCliToolCmd(String cmd) {
		String toolCmd = String.format("%s %s", this.toolName, cmd);
		return toolCmd;
	}
	
	public String runCommand(String command) {
		try {
			BspToolView cliView = BspToolView.getInstance();
			if (cliView != null) {
				ProcessController controller = cliView.getBackend();
				if (controller != null && controller.isRunning()) {
					controller.setTimeout(ToolsUtils.getBspToolTimeout());
					String cmd = getCliToolCmd(command);
					logger.debug("ASCT run command: {}", cmd);
					String ret = controller.runCommand(cmd);
					logger.debug("ASCT output: {}", ret);
					return ret;
				}
			}
		} catch (IOException e) {
			return this.exeTool.launch(this.getExeToolCmd(command));
		}
		return this.exeTool.launch(this.getExeToolCmd(command));
	}

	@Override
	public void createDefaultMss(String mssfile, String chip, String proc, String os) {
		String cmd = String.format(CREATE_DEFAULT_MSS, mssfile, chip, proc, os);
		runCommand(cmd);
	}

	@Override
	public void createMssFromHpf(String hpf, String mssfile, String chip, String proc, String os) {
		String cmd = String.format(CREATE_MSS_FROM_HPF, hpf, mssfile, chip, proc, os);
		runCommand(cmd);
	}

	@Override
	public void reloadMssfile(String mssfile) {
		String cmd = String.format(RELOAD_MSSFILE, mssfile);
		runCommand(cmd);
	}

	@Override
	public String getProcessor(String mssfile) {
		String cmd = String.format(GET_PROCESSOR, mssfile);
		String result = runCommand(cmd).trim();
		JsonObject jsonObject = JsonUtils.readJson(result);
		String targetProc = jsonObject.toString();
		return targetProc;
	}

	@Override
	public OSInfo getOsInfo(String mssfile) {
		String cmd = String.format(GET_OS, mssfile);
		String result = runCommand(cmd).trim();
		OSInfo osInfo = JsonUtils.parse(result, OSInfo.class);
		return osInfo;
	}

	@Override
	public DocInfo getDocInfo(String mssfile) {
		String cmd = String.format(GET_DOC, mssfile);
		String result = runCommand(cmd).trim();
		JsonObject jsonObject = JsonUtils.readJson(result);
		for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
			JsonElement value = entry.getValue();
			DocInfo docInfo = JsonUtils.parse(value.toString(), DocInfo.class);
			return docInfo;
		}
		return null;
	}

	@Override
	public List<DriverInfo> getDriverList(String mssfile) {
		List<DriverInfo> driverList = new ArrayList<DriverInfo>();
		String cmd = String.format(GET_DRIVERS, mssfile);
		String result = runCommand(cmd).trim();
		JsonObject jsonObject = JsonUtils.readJson(result);
		for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
			JsonElement value = entry.getValue();
			DriverInfo driver = JsonUtils.parse(value.toString(), DriverInfo.class);
			driverList.add(driver);
		}
		return driverList;
	}

	@Override
	public DriverInfo getDriver(String mssfile, String name) {
		String cmd = String.format(GET_DRIVER, mssfile, name);
		String result = runCommand(cmd).trim();
		DriverInfo driver = JsonUtils.parse(result, DriverInfo.class);
		return driver;
	}

	@Override
	public void removeDriver(String mssfile, String name) {
		String cmd = String.format(DELETE_DRIVER, mssfile, name);
		runCommand(cmd);
	}

	@Override
	public void addDriver(String mssfile, String name, String version) {
		String cmd = String.format(ADD_DRIVER, mssfile, name, version);
		runCommand(cmd);
	}

	@Override
	public void setDriverVersion(String mssfile, String name, String version) {
		String cmd = String.format(SET_DRIVER_VERSION, mssfile, name, version);
		runCommand(cmd);
	}

	@Override
	public List<LibraryInfo> getLibraryList(String mssfile) {
		List<LibraryInfo> libList = new ArrayList<LibraryInfo>();
		String cmd = String.format(GET_LIBRARIES, mssfile);
		String result = runCommand(cmd).trim();
		JsonObject jsonObject = JsonUtils.readJson(result);
		for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
			JsonElement value = entry.getValue();
			LibraryInfo lib = JsonUtils.parse(value.toString(), LibraryInfo.class);
			libList.add(lib);
		}
		return libList;
	}

	@Override
	public LibraryInfo getLibrary(String mssfile, String name) {
		String cmd = String.format(GET_LIBRARY, mssfile, name);
		String result = runCommand(cmd).trim();
		LibraryInfo lib = JsonUtils.parse(result, LibraryInfo.class);
		return lib;
	}

	@Override
	public void removeLibrary(String mssfile, String name) {
		String cmd = String.format(DELETE_LIBRARY, mssfile, name);
		runCommand(cmd);
	}

	@Override
	public void addLibrary(String mssfile, String name, String version) {
		String cmd = String.format(ADD_LIBRARY, mssfile, name, version);
		runCommand(cmd);
	}

	@Override
	public void setLibraryVersion(String mssfile, String name, String version) {
		String cmd = String.format(SET_LIBRARY_VERSION, mssfile, name, version);
		runCommand(cmd);
	}

	@Override
	public void generteBsp(String hpfPath, String mssfile, String bspLocation) {
		String cmd = String.format(GENERATE_BSP_RESOURCE, hpfPath, mssfile, bspLocation);
		runCommand(cmd);
	}

	@Override
	public void regenerateBsp(String mssfile, String bspLocation) {
		String cmd = String.format(REGENERATE_BSP_RESOURCE, mssfile, bspLocation);
		runCommand(cmd);
	}

	@Override
	public List<String> getAppNames(String os, String chip, String proc) {
		String cmd = String.format(GET_APP_NAMES, os, chip, proc);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}
	
	@Override
	public List<String> getLinuxAppNames(String chip, String proc) {
		String cmd = String.format(GET_LINUX_APP_NAMES, chip, proc);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public String getAppDesc(String appName) {
		String cmd = String.format(GET_APP_DESC, appName);
		String result = runCommand(cmd).trim();
		return result;
	}

	@Override
	public List<String> getAppLibs(String appName) {
		String cmd = String.format(GET_APP_LIBS, appName);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public List<String> getAppExtraLibs(String mssfile, String appName) {
		String cmd = String.format(GET_APP_EXTRA_LIBS, mssfile, appName);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public Map<String, String> getAppBuildProperties(String appName) {
		String cmd = String.format(GET_APP_BUILD_PROPERTIES, appName);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToMap(result);
	}

	@Override
	public void generateApp(String bspPath, String appName, String appLocation) {
		String cmd = String.format(GENERATE_APP_RESOURCE, bspPath, appName, appLocation);
		runCommand(cmd);
	}
	
	@Override
	public void updateAppLinkscript(String bspLocation, String appLocation) {
		String cmd = String.format(UPDATE_APP_LINKSCRIPT, bspLocation, appLocation);
		runCommand(cmd);
	}

	public String getName(String name) {
		String ret = "";
		String pattern = "(\\w+?)_V[\\d+]_[\\d+]";
		Pattern r = Pattern.compile(pattern);
		Matcher m = r.matcher(name);
		if (m.find()) {
			ret = m.group(1);
		}
		return ret;
	}

	public String getVersion(String name) {
		String ret = "";
		String pattern = "\\w+([\\d+]_[\\d+])";
		Pattern r = Pattern.compile(pattern);
		Matcher m = r.matcher(name);
		if (m.find()) {
			ret = m.group(1);
			ret = ret.replace("_", ".");
		}
		return ret;
	}

	public String getFullName(String name, String version) {
		String ret = name + "_V" + version.replace(".", "_");
		return ret;
	}

	@Override
	public List<String> getDriverAppNames(String driverName, String os, String chip, String proc) {
		String cmd = String.format(GET_DRIVER_APP_NAMES, driverName, os, chip, proc);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public String getChipFromHpf(String hpf) {
		String cmd = String.format(GET_CHIP_FROM_HPF, hpf);
		String result = runCommand(cmd).trim();
		return result;
	}

	@Override
	public List<String> getIncludePaths(String dir) {
		String cmd = String.format(GET_INCLUDE_PATHS, dir);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public List<String> getLinkScripts(String appLocation, String chip, String download) {
		String cmd = String.format(GET_LINK_SCRIPTS, appLocation, chip, download);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public void updateBspHpf(String bspLocation, String hpf) {
		String cmd = String.format(UPDATE_BSP_HPF, bspLocation, hpf);
		runCommand(cmd);
	}

	@Override
	public List<String> getOsNames() {
		String cmd = String.format(GET_OS_NAMES);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public List<String> getDriverNames() {
		String cmd = String.format(GET_DRIVER_NAMES);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public List<String> getLibraryNames() {
		String cmd = String.format(GET_LIBRARY_NAMES);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public List<String> getOsVersions(String name) {
		name = name.toUpperCase();
		if (!name.startsWith("OS_"))
			name = "OS_" + name;
		String cmd = String.format(GET_OS_VERSIONS, name);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public List<String> getDriverVersions(String name) {
		String cmd = String.format(GET_DRIVER_VERSIONS, name);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public List<String> getLibraryVersions(String name) {
		String cmd = String.format(GET_LIBRARY_VERSIONS, name);
		String result = runCommand(cmd).trim();
		return StringUtils.convertToList(result);
	}

	@Override
	public List<String> getLibDescFromCfgFile(String name) {
		List<String> versList = this.getLibraryVersions(name);
		List<String> descList = new ArrayList<String>();
		for (String ver : versList) {
			descList.add(this.getLibraryFromCfgFile(name, ver).getDesc());
		}
		return descList;
	}

	@Override
	public OSInfo getOsFromCfgFile(String name, String version) {
		String cmd = String.format(GET_OS_FROM_CFGFILE, name, version);
		String result = runCommand(cmd).trim();
		OSInfo osInfo = JsonUtils.parse(result, OSInfo.class);
		return osInfo;
	}

	@Override
	public DriverInfo getDriverFromCfgFile(String name, String version) {
		String cmd = String.format(GET_DRIVER_FROM_CFGFILE, name, version);
		String result = runCommand(cmd).trim();
		DriverInfo driverInfo = JsonUtils.parse(result, DriverInfo.class);
		return driverInfo;
	}

	@Override
	public LibraryInfo getLibraryFromCfgFile(String name, String version) {
		String cmd = String.format(GET_LIBRARY_FROM_CFGFILE, name, version);
		String result = runCommand(cmd).trim();
		LibraryInfo libInfo = JsonUtils.parse(result, LibraryInfo.class);
		return libInfo;
	}
	
	@Override
	public void processAppMakefile(String bspLocation, String appLocation, String appName) {
		String cmd = String.format(PROCESS_APP_MAKEFILE, bspLocation, appLocation, appName);
		runCommand(cmd);
	}
}
